#ifndef __CLIENT_SOCKET__H_8DF54DBF_E2A9_48EA_91F5_7C64D2628E74
#define __CLIENT_SOCKET__H_8DF54DBF_E2A9_48EA_91F5_7C64D2628E74

#include "Object.h"
#include "Msg.h"
#include "CBuff.h"

#define HEART_TIMESTAMP     60000
#define SEND_DATA_TIMEUP    200

using namespace std::chrono;
class CNowTime
{
public:
	static time_t GetNowTime() {
        return duration_cast<milliseconds>(high_resolution_clock::now().time_since_epoch()).count();
	}
};

typedef enum _IORQ
{
    IORQ_CONNECT,
    IORQ_ACCEPT,
    IORQ_RECV,
    IORQ_SEND
}IORQ;

typedef struct _IO_EVENT
{
    OVERLAPPED Overlapped;
    SOCKET Socket;
    WSABUF WsaBuff;
    DWORD dwBytes;
    IORQ Type;
}IO_EVENT, * PIO_EVENT;

class CClientSocket
{
protected:
    SOCKET m_Socket;
    time_t m_Heart;

public:
    CClientSocket(IN SOCKET socket = INVALID_SOCKET) { m_Socket = socket; ResetHeart(); }
    ~CClientSocket() { 
        Close();
    }

public:
    inline SOCKET GetSocket() const { return m_Socket; }
    inline void SetSocket(IN SOCKET socket) { m_Socket = socket; }
    inline void Close() { if (m_Socket != INVALID_SOCKET) { CloseSocket(m_Socket); m_Socket = INVALID_SOCKET; } }

    void ResetHeart() { m_Heart = 0; }
    BOOL isAlive(IN time_t t) { m_Heart += t; return !(m_Heart >= HEART_TIMESTAMP); }
};

#define RECV_BUFF_SIZE  8192
#define SEND_BUFF_SIZE  10240

class CSocket : public CClientSocket
{
protected:
    char m_strRecvBuff[RECV_BUFF_SIZE];
    CSendBuff m_SendBuff;
    CRecvBuff m_RecvBuff;
    int m_nRecvEndPos;
    time_t m_SendTimeStamp;

public:
    CSocket(IN SOCKET socket = INVALID_SOCKET) : 
        CClientSocket(socket), 
        m_SendBuff(SEND_BUFF_SIZE), 
        m_RecvBuff(RECV_BUFF_SIZE)
    {
        ResetSendTime();
    }
    ~CSocket() {}

    inline void ResetSendTime() { m_SendTimeStamp = 0; }
    void CheckSendTime(IN time_t t) {
        m_SendTimeStamp += t;
        if (m_SendTimeStamp >= SEND_DATA_TIMEUP) {
            Send(); ResetSendTime();
        }
    }

public:
    inline int Send() { int nRetLen = m_SendBuff.Send(m_Socket); ResetSendTime(); return nRetLen; }
    inline int Recv() { int nRetLen = m_RecvBuff.Recv(m_Socket); return nRetLen; }
    inline NET_PACKET_HEADER* GetFirstMsg() const { return ((NET_PACKET_HEADER*)(m_RecvBuff.GetBuff())); }

    int SendAsyn(IN NET_PACKET_HEADER* pHeader);
    int Send(IN NET_PACKET_HEADER* pHeader) {
        SendAsyn(pHeader);
        return Send();
    }

    BOOL isFullMsg();
    BOOL RemoveHeadMsg();
};

class CSelSocket : public CSocket
{
public:
    CSelSocket(IN SOCKET socket = INVALID_SOCKET) : CSocket(socket) {  }
    ~CSelSocket() {  }
};

class CIoSocket : public CSocket
{
private:
    BOOL m_bRecving;
    BOOL m_bSending;
    BOOL m_bRemove;
    IO_EVENT m_RecvEvent;
    IO_EVENT m_SendEvent;

public:
    CIoSocket() {
        m_bRecving = m_bSending = m_bRemove = FALSE;
        RtlZeroMemory(&m_RecvEvent, sizeof(IO_EVENT));
        RtlZeroMemory(&m_SendEvent, sizeof(IO_EVENT));
    }
    ~CIoSocket() { }

public:
    PIO_EVENT GetRecvEvent() {
        if (!m_bRecving)
        {
            m_bRecving = TRUE;
            if (m_RecvBuff.GetBuffSize() - m_RecvBuff.GetEndPos() > 0)
            {
                m_RecvEvent.WsaBuff.buf = m_RecvBuff.GetBuff() + m_RecvBuff.GetEndPos();
                m_RecvEvent.WsaBuff.len = m_RecvBuff.GetBuffSize() - m_RecvBuff.GetEndPos();
                m_RecvEvent.Socket = GetSocket();
                return &m_RecvEvent;
            }
        }
        return nullptr;
    }

    PIO_EVENT GetSendEvent() {
        if (!m_bSending)
        {
            m_bSending = TRUE;
            if (m_SendBuff.GetEndPos() > 0)
            {
                m_SendEvent.WsaBuff.buf = m_SendBuff.GetBuff();
                m_SendEvent.WsaBuff.len = m_SendBuff.GetEndPos();
                m_SendEvent.Socket = GetSocket();
                return &m_SendEvent;
            }
        }
        return nullptr;
    }

    inline BOOL UpdateRecvBuffPos(IN UINT len) { 
        assert(m_bRecving == TRUE);
        m_bRecving = FALSE;
        return m_RecvBuff.AdvanceEndPos(len); 
    }

    inline BOOL UpdateSendBuffPos(IN UINT StartPos) { 
        assert(m_bSending == TRUE);
        m_bSending = FALSE;
        return m_SendBuff.AdvanceMoveBuffMemory(StartPos); 
    }

    inline void SetRemove() { m_bRemove = TRUE; }
    inline BOOL NeedToSend() const { return (!m_SendBuff.Empty()); }
    inline BOOL NeedToRecv() const { return (!m_RecvBuff.Empty()); }
    inline BOOL NeedToRemove() const { return m_bRemove; }

    inline BOOL isActing() const { return (m_bRecving || m_bSending); }
};


#endif
